﻿using Microsoft.Win32;
using SerialPortHelper.utils;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;

namespace SerialPortHelper
{
    public partial class Form1 : Form
    {
        private bool isReceiveStop = false;

        private List<byte> receiveBuffer = new List<byte>();
        private List<Byte> sendBuffer = new List<byte>();

        // 创建委托类型的成员变量
        // public TransmitData transimitData;

        // IDLE Timer
        private System.Timers.Timer idleTimer;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Serial_Load();

            btnStopReceive.BackColor = Color.Green;

            // 当窗体1加载的时候，就将窗口2加载出来
            Form2 fr2 = new Form2();
            // 使用子窗口的函数初始化当前窗口的委托对象
            //transimitData = new TransmitData(fr2.ReceiveData);
            //fr2.Show();

            // IDLE Timer 初始化
            idleTimer = new System.Timers.Timer(50);
            idleTimer.AutoReset = false;
            idleTimer.Elapsed += TimerElapsed;

            // CRC 计算下拉框
            ccbCRC.SelectedIndex = 0;
            btnCRCComputed.Enabled = false;
        }
        
        private void TimerElapsed(object sender, ElapsedEventArgs e)
        {
            
        }

        /// <summary>
        /// 重置 Timer 计数器
        /// </summary>
        private void Reset_IdleTimer()
        { 
            idleTimer.Stop();
            idleTimer.Start();
        }

        /// <summary>
        /// 串口加载
        /// </summary>
        private void Serial_Load()
        {
            // 注册列表当中搜索可用串口
            //RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");
            //string[]  SubKeys = keyCom.GetValueNames();
            //cbbPort.Items.Clear();
            //foreach (var key in SubKeys)
            //{
            //    cbbPort.Items.Add(keyCom.GetValue(key)).ToString();
            //}
            string[] portNames = SerialPort.GetPortNames();
            cbbPort.Items.Clear();
            cbbPort.Items.AddRange(portNames);

            // 下拉框初始值设置
            if (cbbPort.Items.Count != 0)
            {
                cbbPort.SelectedIndex = 0;
            }
            this.cbbBuad.SelectedIndex = 0;
            this.cbbCheck.SelectedIndex = 0;
            this.cbbDataBit.SelectedIndex = 3;
            this.cbbStopBit.SelectedIndex = 0;
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            // 数据不为空，则可以发送数据
            if (this.rTxtSend.Text != "")
            {
                this.rTxtReceive.AppendText(this.rTxtSend.Text);
            }
        }
        /// <summary>
        /// 打开串口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void checkBox2_CheckedChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            try
            {
                // 打开串口
                if (btnOpen.Text == "打开串口")
                {
                    if (cbbPort.Text != "")
                    {
                        // 更新串口组件的属性
                        serialPort1.PortName = cbbPort.Text;
                        serialPort1.BaudRate = Convert.ToInt32(cbbBuad.Text);
                        serialPort1.DataBits = Convert.ToInt32(cbbDataBit.Text);
                        switch (cbbCheck.SelectedIndex)
                        {
                            case 0:
                                serialPort1.Parity = Parity.None;
                                break;
                            case 1:
                                serialPort1.Parity = Parity.Odd;
                                break;
                            case 2:
                                serialPort1.Parity = Parity.Even;
                                break;
                            default:
                                break;
                        }
                        switch (cbbStopBit.SelectedIndex)
                        {
                            case 0:
                                serialPort1.StopBits = StopBits.One;
                                break;
                            case 1:
                                serialPort1.StopBits = StopBits.OnePointFive;
                                break;
                            case 2:
                                serialPort1.StopBits = StopBits.Two;
                                break;
                            default:
                                break;
                        }

                        // 使用组件的默认属性暂时打开串口
                        serialPort1.Open();

                        if (serialPort1.IsOpen)
                        {
                            MessageBox.Show("串口" + cbbPort.Text + "打开成功");
                            btnOpen.Text = "关闭串口";
                        }
                    }
                    else
                    {
                        MessageBox.Show("请选择 Com 口");
                    }
                }
                else
                {
                    serialPort1.Close();
                    if (!serialPort1.IsOpen)
                    {
                        MessageBox.Show("关闭成功");
                        btnOpen.Text = "打开串口";
                    }
                }

            }
            catch (Exception exception)
            {
                // 将错误暂时使用 MessageBox 输出, 避免程序卡死
                MessageBox.Show(exception.ToString() + serialPort1.PortName.ToString());
            }


        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button9_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen && sendBuffer.Count != 0 )
            {
                serialPort1.Write(sendBuffer.ToArray(), 0, sendBuffer.Count);

                // 更新发送数量
                tsslSendCounter.Text = Int32.Parse(tsslSendCounter.Text) + sendBuffer.Count + "";
            }
        }

        private void label6_Click(object sender, EventArgs e)
        {

        }

        private void toolStripStatusLabel4_Click(object sender, EventArgs e)
        {

        }

        private void rTxtReceive_TextChanged(object sender, EventArgs e)
        {

        }

        private void groupBox1_Enter(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// 串口数据接收事件, 注意 serialPort 这个事件响应是单独的一个线程, 不要在这个线程
        /// 当中去接收数据。
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            // 刷新定时器
            Reset_IdleTimer();
            
            // 读取全部接收到的数据
            byte[] dataTemp = new byte[serialPort1.BytesToRead];
            serialPort1.Read(dataTemp, 0, dataTemp.Length);

            // 向缓冲中增加数据
            receiveBuffer.AddRange(dataTemp);

            // 当接收数据不为空的时候，调用下委托, 将数据传递给其他窗口
            // transimitData?.Invoke(dataTemp);

            // 更新页面的组件内容, 使用 Invoke 将 UI 操作封送给到主线程
            if (this.InvokeRequired && !isReceiveStop)
            {
                this.Invoke(new Action(() =>
                {
                    // 编码格式判断, 当未勾选 16 进制选项时, 此时按照 GB2312 方式处理。
                    if (!chbHexReceive.Checked)
                    {
                        rTxtReceive.AppendText(Encoding.GetEncoding("gb2312").GetString(dataTemp).Replace("\0", "\\0"));
                    }
                    // 16 进制
                    else
                    {
                        rTxtReceive.AppendText(CodeUtils.BytesToHexString(dataTemp, " ", true));
                    }

                    // 更新接收字节数
                    tsslReceiveCounter.Text = Int32.Parse(tsslReceiveCounter.Text) + dataTemp.Length + "";
                }));
            }
        }

        /// <summary>
        /// 暂停开启接收
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnStopReceive_Click(object sender, EventArgs e)
        {
            isReceiveStop = !isReceiveStop;
            btnStopReceive.Text = isReceiveStop ? "开启" : "暂停";
            btnStopReceive.BackColor = isReceiveStop ? Color.Red : Color.Green;
        }

        private void chbHexReceive_CheckedChanged(object sender, EventArgs e)
        {

            if (rTxtReceive.Text == "")
                return;

            if (!chbHexReceive.Checked)
            {
                rTxtReceive.Text = Encoding.GetEncoding("gb2312").GetString(receiveBuffer.ToArray()).Replace("\0", "\\0");
            }
            else
            {
                rTxtReceive.Text = CodeUtils.BytesToHexString(receiveBuffer.ToArray(), " ", true);
            }
        }

        private void btnCleanReceive_Click(object sender, EventArgs e)
        {
            receiveBuffer.Clear();
            rTxtReceive.Clear();
        }

        private void RefreshSendBuffer()
        {
            if (string.IsNullOrEmpty(rTxtSend.Text))
            {
                sendBuffer.Clear();
                return;
            }

            sendBuffer.Clear();

            if (chbHexSend.Checked)
            {
                if (!CodeUtils.IsHexString(rTxtSend.Text, true))
                {
                    MessageBox.Show("请输入 16 进制字符串");
                }
                // 焦点失去 且 16 进制, 则清空 SendBuffer，并完成一次转换
                else
                {
                    sendBuffer.Clear();

                    // 将输入框内容转换为 16 进制数据发送
                    sendBuffer.AddRange(CodeUtils.HexStrToByteArr(rTxtSend.Text));
                }
            }
            else
            {
                // 将内容按照 GB2312 编码
                sendBuffer.Clear();
                sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(rTxtSend.Text));
            }
        }

        /// <summary>
        /// 发送框失去焦点时, 检查输入框内是否满足 16 进制数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void rTxtSend_Leave(object sender, EventArgs e)
        {
            RefreshSendBuffer();
        }

        /// <summary>
        /// 勾选和取消勾选时, 需要根据输入内容重重新将输入框内容更新到 SendBuffer 中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void chbHexSend_CheckedChanged(object sender, EventArgs e)
        {
            RefreshSendBuffer();
        }

        private void btnClearSendArea_Click(object sender, EventArgs e)
        {
            rTxtSend.Clear();
            sendBuffer.Clear();
            tsslSendCounter.Text = "0";
        }

        private void btnRefresh_Click(object sender, EventArgs e)
        {
            string[] portNames = SerialPort.GetPortNames();
            cbbPort.Items.Clear();
            cbbPort.Items.AddRange(portNames);
        }

        private void rTxtCRCSource_TextChanged(object sender, EventArgs e)
        {
            btnCRCComputed.Enabled = rTxtCRCSource.Text != "";
        }

        private void btnCRCComputed_Click(object sender, EventArgs e)
        {
            // 检查是否是 16 进制字符串
            if (!CodeUtils.IsHexString(rTxtCRCSource.Text, true))
            {
                MessageBox.Show("请输入正确的16进制值");
                return;
            }

            if (ccbCRC.SelectedIndex == 0) // MODBUS/CRC16
            {
                ushort CRC16 = CRCUtils.Get_ModbusCRC16(CodeUtils.HexStrToByteArr(rTxtCRCSource.Text));
                txtCRCOutput.Text = CRC16.ToString("X4");
            }
        }


        private void button1_Click_1(object sender, EventArgs e)
        {
            uint result = 0;
            for (int i = 0; i < 32; i++)
            {
                string checkBoxName = $"CheckBoxRegBit{i}";
                CheckBox checkBox = Controls.Find(checkBoxName, true).FirstOrDefault() as CheckBox;
                if (checkBox != null && checkBox.Checked)
                {
                    result |= (uint)(1 << i); // 设置对应的位为 1
                }
            }

            string hexString = result.ToString("X8");
            textBoxRegister.Text = "0x" + hexString;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 32; i++)
            {
                string checkBoxName = $"CheckBoxRegBit{i}";
                CheckBox checkBox = Controls.Find(checkBoxName, true).FirstOrDefault() as CheckBox;
                if (checkBox != null)
                {
                    checkBox.Checked = false;
                }
            }
            textBoxRegister.Text = "";
        }
    }
}
